package com.inplaceedit.shared.webservice.impl.data;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.gwt.i18n.client.DateTimeFormat;

public class Data {
	private static Data INSTANCE;

	public static Data get() {
		if (INSTANCE == null) {
			INSTANCE = new Data();
		}
		return INSTANCE;
	}

	private final Map<String, Contact> contactIdIndex;
	private final Map<String, Company> companyIdIndex;
	private final Map<String, Note> noteIdIndex;
	private final Map<String, Set<String>> noteContactIndex;

	long nextId;

	private Data() {
		nextId = 0;
		contactIdIndex = new HashMap<String, Contact>();
		companyIdIndex = new HashMap<String, Company>();
		noteIdIndex = new HashMap<String, Note>();
		noteContactIndex = new HashMap<String, Set<String>>();
		populate();
	}

	public Note deleteNote(final Note object) {
		final Note toDelete = noteIdIndex.get(object.getId());
		if (toDelete != null) {
			noteIdIndex.remove(toDelete.getId());
			final Set<String> contactNotes = noteContactIndex.get(toDelete
					.getContactId());
			if (contactNotes != null) {
				contactNotes.remove(toDelete.getId());
			}
		}
		return toDelete;
	}

	public Company getCompany(final String id) {
		return companyIdIndex.get(id);
	}

	public List<Company> getCompanyList() {
		final List<Company> result = new ArrayList<Company>();
		result.addAll(companyIdIndex.values());
		Collections.sort(result, new Comparator<Company>() {
			@Override
			public int compare(final Company o1, final Company o2) {
				final String name1 = o1.getName() != null ? o1.getName() : "";
				final String name2 = o2.getName() != null ? o2.getName() : "";
				return name1.compareTo(name2);
			}
		});
		return result;
	}

	public Contact getContact(final String id) {
		return contactIdIndex.get(id);
	}

	public List<Contact> getContactList() {
		final List<Contact> result = new ArrayList<Contact>();
		result.addAll(contactIdIndex.values());
		return result;
	}

	public Note getNote(final String id) {
		return noteIdIndex.get(id);
	}

	public List<Note> getNoteList(final String contactId) {
		final List<Note> result = new ArrayList<Note>();
		final Set<String> contactNotes = noteContactIndex.get(contactId);
		if (contactNotes != null) {
			for (final String noteId : contactNotes) {
				result.add(noteIdIndex.get(noteId));
			}
		}
		Collections.sort(result, new Comparator<Note>() {
			@Override
			public int compare(final Note o1, final Note o2) {
				final String t1 = (o1.getTime() != null) ? DateTimeFormat
						.getFormat("yyyyMMddHHmmss").format(o1.getTime())
						: "00000000000000";
				final String t2 = (o2.getTime() != null) ? DateTimeFormat
						.getFormat("yyyyMMddHHmmss").format(o2.getTime())
						: "00000000000000";
				return t2.compareTo(t1);
			}
		});
		return result;
	}

	public Company saveCompany(final Company object) {
		if (object.getId() == null) {
			object.setId(getNextId());
		}
		companyIdIndex.put(object.getId(), object);
		return object;
	}

	public Contact saveContact(final Contact object) {
		if (object.getId() == null) {
			object.setId(getNextId());
		}
		contactIdIndex.put(object.getId(), object);
		return object;
	}

	public Note saveNote(final Note object) {
		if (object.getId() == null) {
			object.setId(getNextId());
		}
		noteIdIndex.put(object.getId(), object);
		Set<String> contactNotes = noteContactIndex.get(object.getContactId());
		if (contactNotes == null) {
			contactNotes = new HashSet<String>();
			noteContactIndex.put(object.getContactId(), contactNotes);
		}
		contactNotes.add(object.getId());
		return object;
	}

	private String getNextId() {
		final String result = String.valueOf(nextId);
		nextId++;
		return result;
	}

	private void populate() {
		final Company[] companies = new Company[3];

		companies[0] = new Company();
		companies[0].setName("Google, Inc.");

		companies[1] = new Company();
		companies[1].setName("Apple");

		companies[2] = new Company();
		companies[2].setName("Microsoft");

		for (final Company company : companies) {
			saveCompany(company);
		}

		final Contact contact = new Contact();
		contact.setId("test");
		contact.setFirstName("Joe");
		contact.setLastName("Doe");
		contact.setTitle("Code jockey");
		contact.setCompanyId(companies[1].getId());
		contact.setBirthday(DateTimeFormat.getFormat("MM/dd/yyyy").parse(
				"01/01/1980"));
		contact.setSex(Contact.Sex.MALE);
		contact.setPhoneList(new ArrayList<Phone>());

		final Phone[] phones = new Phone[2];

		phones[0] = new Phone();
		phones[0].setType(Phone.Type.HOME);
		phones[0].setNumber("+1 (610) 610-6100");

		phones[1] = new Phone();
		phones[1].setType(Phone.Type.CELL);
		phones[1].setNumber("+1 (610) 610-6101");

		for (final Phone phone : phones) {
			contact.getPhoneList().add(phone);
		}

		saveContact(contact);

		final Note[] notes = new Note[2];

		notes[0] = new Note();
		notes[0].setContactId(contact.getId());
		notes[0].setTime(DateTimeFormat.getFormat("MM/dd/yyyy HH:mm:ss").parse(
				"06/01/2011 11:23:15"));
		notes[0].setText("Had a good chat re in-place editing.");

		notes[1] = new Note();
		notes[1].setContactId(contact.getId());
		notes[1].setTime(DateTimeFormat.getFormat("MM/dd/yyyy HH:mm:ss").parse(
				"06/15/2011 15:11:01"));
		notes[1].setText("Things seem to be going well.");

		for (final Note note : notes) {
			saveNote(note);
		}
	}
}
